"""PPG信号时间戳处理示例

演示如何使用PPGSignal的时间戳功能来处理带有时间戳的PPG数据，
包括丢包检测、插值修复等功能。

作者: PPG算法包开发团队
版本: 2.0.0
"""

import numpy as np
import matplotlib.pyplot as plt
from typing import Dict, Any, List
import warnings

import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from core.data_types import PPGSignal
from core.processor_manager import PPGProcessorManager


def create_ppg_with_timestamps(duration: float = 30.0, 
                              sampling_rate: float = 100.0,
                              heart_rate: float = 70.0,
                              packet_loss_ratio: float = 0.05) -> PPGSignal:
    """创建带时间戳的PPG信号，模拟丢包情况
    
    参数:
        duration: 信号时长（秒）
        sampling_rate: 采样率（Hz）
        heart_rate: 心率（BPM）
        packet_loss_ratio: 丢包率（0-1）
        
    返回:
        PPGSignal: 带时间戳的PPG信号
    """
    # 生成理想的时间轴和信号
    total_samples = int(duration * sampling_rate)
    ideal_timestamps = np.linspace(0, duration, total_samples)
    
    # 生成PPG信号
    frequency = heart_rate / 60  # Hz
    ppg_data = np.sin(2 * np.pi * frequency * ideal_timestamps)
    ppg_data += 0.3 * np.sin(2 * np.pi * 2 * frequency * ideal_timestamps)  # 谐波
    ppg_data += 0.1 * np.random.randn(total_samples)  # 噪声
    
    # 模拟丢包：随机删除一些数据点
    if packet_loss_ratio > 0:
        keep_indices = np.random.rand(total_samples) > packet_loss_ratio
        actual_timestamps = ideal_timestamps[keep_indices]
        actual_data = ppg_data[keep_indices]
    else:
        actual_timestamps = ideal_timestamps
        actual_data = ppg_data
    
    return PPGSignal(
        data=actual_data,
        sampling_rate=sampling_rate,
        timestamps=actual_timestamps,
        metadata={
            'simulated': True,
            'original_length': total_samples,
            'actual_length': len(actual_data),
            'packet_loss_ratio': packet_loss_ratio
        }
    )


def analyze_timestamp_signal(signal: PPGSignal) -> Dict[str, Any]:
    """分析带时间戳的PPG信号
    
    参数:
        signal: PPG信号
        
    返回:
        Dict: 分析结果
    """
    print(f"=== PPG信号时间戳分析 ===")
    print(f"信号长度: {signal.length} 个采样点")
    print(f"采样率: {signal.sampling_rate} Hz")
    print(f"是否有时间戳: {signal.has_timestamps}")
    
    if signal.has_timestamps:
        print(f"实际时长: {signal.duration:.2f} 秒")
        print(f"理论时长: {signal.theoretical_duration:.2f} 秒")
        print(f"时间覆盖率: {signal.duration/signal.theoretical_duration*100:.1f}%")
        
        # 丢包检测
        packet_loss_info = signal.detect_packet_loss()
        print(f"\n--- 丢包检测结果 ---")
        print(f"检测到丢包: {packet_loss_info['has_packet_loss']}")
        if packet_loss_info['has_packet_loss']:
            print(f"异常间隔数: {packet_loss_info['total_gaps']}")
            print(f"明显丢包数: {packet_loss_info['large_gaps']}")
            print(f"丢包率: {packet_loss_info['packet_loss_ratio']*100:.1f}%")
            print(f"时间覆盖率: {packet_loss_info['time_coverage']*100:.1f}%")
            print(f"平均间隔: {packet_loss_info['mean_interval']*1000:.2f} ms")
            print(f"间隔标准差: {packet_loss_info['std_interval']*1000:.2f} ms")
            print(f"理论间隔: {packet_loss_info['theoretical_interval']*1000:.2f} ms")
        
        return packet_loss_info
    else:
        print("无时间戳信息")
        return {}


def demonstrate_interpolation(signal: PPGSignal) -> PPGSignal:
    """演示插值修复功能
    
    参数:
        signal: 原始信号
        
    返回:
        PPGSignal: 插值后的信号
    """
    print(f"\n=== 插值修复演示 ===")
    
    if not signal.has_timestamps:
        print("无时间戳信息，无法进行插值")
        return signal
    
    packet_loss_info = signal.detect_packet_loss()
    if not packet_loss_info['has_packet_loss']:
        print("无丢包，不需要插值")
        return signal
    
    print(f"原始信号长度: {signal.length}")
    print(f"原始信号时长: {signal.duration:.2f} 秒")
    
    # 线性插值
    interpolated_signal = signal.interpolate_missing_data(method='linear')
    
    print(f"插值后信号长度: {interpolated_signal.length}")
    print(f"插值后信号时长: {interpolated_signal.duration:.2f} 秒")
    print(f"插值方法: {interpolated_signal.metadata.get('interpolation_method', 'unknown')}")
    
    # 验证插值效果
    new_packet_loss_info = interpolated_signal.detect_packet_loss()
    print(f"插值后丢包检测: {new_packet_loss_info['has_packet_loss']}")
    
    return interpolated_signal


def compare_processing_results(original_signal: PPGSignal, 
                             interpolated_signal: PPGSignal) -> None:
    """比较原始信号和插值信号的处理结果
    
    参数:
        original_signal: 原始信号
        interpolated_signal: 插值信号
    """
    print(f"\n=== 处理结果对比 ===")
    
    # 创建处理器
    processor = PPGProcessorManager()
    
    try:
        # 处理原始信号
        original_results = processor.process_signal(
            original_signal, 
            pipeline_name="custom_optimal"
        )
        
        # 处理插值信号
        interpolated_results = processor.process_signal(
            interpolated_signal,
            pipeline_name="custom_optimal"
        )
        
        print(f"原始信号处理结果:")
        print(f"  检测峰值: {len(original_results.peaks)}")
        print(f"  平均心率: {original_results.mean_heart_rate:.1f} BPM")
        if original_results.quality_results:
            print(f"  信号质量: {original_results.quality_results.quality_grade}")
            print(f"  质量评分: {original_results.quality_results.quality_score:.1f}")
        
        print(f"\n插值信号处理结果:")
        print(f"  检测峰值: {len(interpolated_results.peaks)}")
        print(f"  平均心率: {interpolated_results.mean_heart_rate:.1f} BPM")
        if interpolated_results.quality_results:
            print(f"  信号质量: {interpolated_results.quality_results.quality_grade}")
            print(f"  质量评分: {interpolated_results.quality_results.quality_score:.1f}")
        
        # 计算改善程度
        peak_improvement = len(interpolated_results.peaks) - len(original_results.peaks)
        hr_diff = abs(interpolated_results.mean_heart_rate - original_results.mean_heart_rate)
        
        print(f"\n改善效果:")
        print(f"  峰值检测改善: {peak_improvement:+d} 个")
        print(f"  心率差异: {hr_diff:.1f} BPM")
        
        if (original_results.quality_results and 
            interpolated_results.quality_results):
            quality_improvement = (interpolated_results.quality_results.quality_score - 
                                 original_results.quality_results.quality_score)
            print(f"  质量评分改善: {quality_improvement:+.1f} 分")
        
    except Exception as e:
        print(f"处理过程中出现错误: {e}")


def visualize_timestamp_analysis(signal: PPGSignal, 
                               interpolated_signal: PPGSignal = None,
                               save_path: str = None) -> None:
    """可视化时间戳分析结果
    
    参数:
        signal: 原始信号
        interpolated_signal: 插值信号（可选）
        save_path: 保存路径（可选）
    """
    try:
        import matplotlib.pyplot as plt
    except ImportError:
        print("需要安装matplotlib库才能使用可视化功能")
        return
    
    fig, axes = plt.subplots(2, 2, figsize=(15, 10))
    fig.suptitle('PPG信号时间戳分析', fontsize=16)
    
    # 1. 原始信号时域图
    time_axis = signal.get_time_axis()
    axes[0, 0].plot(time_axis, signal.data, 'b-', alpha=0.7, label='原始信号')
    if interpolated_signal is not None:
        interp_time_axis = interpolated_signal.get_time_axis()
        axes[0, 0].plot(interp_time_axis, interpolated_signal.data, 'r-', 
                       alpha=0.5, label='插值信号')
    axes[0, 0].set_xlabel('时间 (秒)')
    axes[0, 0].set_ylabel('幅值')
    axes[0, 0].set_title('信号时域对比')
    axes[0, 0].legend()
    axes[0, 0].grid(True, alpha=0.3)
    
    # 2. 时间间隔分析
    if signal.has_timestamps and len(signal.timestamps) > 1:
        intervals = np.diff(signal.timestamps) * 1000  # 转换为毫秒
        theoretical_interval = 1000 / signal.sampling_rate
        
        axes[0, 1].hist(intervals, bins=50, alpha=0.7, color='blue', edgecolor='black')
        axes[0, 1].axvline(theoretical_interval, color='red', linestyle='--', 
                          label=f'理论间隔: {theoretical_interval:.1f} ms')
        axes[0, 1].set_xlabel('时间间隔 (ms)')
        axes[0, 1].set_ylabel('频次')
        axes[0, 1].set_title('时间间隔分布')
        axes[0, 1].legend()
        axes[0, 1].grid(True, alpha=0.3)
    else:
        axes[0, 1].text(0.5, 0.5, '无时间戳信息', ha='center', va='center', 
                       transform=axes[0, 1].transAxes)
        axes[0, 1].set_title('时间间隔分布')
    
    # 3. 丢包检测可视化
    if signal.has_timestamps:
        packet_loss_info = signal.detect_packet_loss()
        if packet_loss_info['has_packet_loss']:
            gap_indices = packet_loss_info['gap_indices']
            # 标记丢包位置
            for idx in gap_indices[:10]:  # 只显示前10个
                if idx < len(time_axis) - 1:
                    axes[1, 0].axvspan(time_axis[idx], time_axis[idx+1], 
                                     alpha=0.3, color='red', label='丢包区域' if idx == gap_indices[0] else "")
        
        axes[1, 0].plot(time_axis, signal.data, 'b-', alpha=0.7)
        axes[1, 0].set_xlabel('时间 (秒)')
        axes[1, 0].set_ylabel('幅值')
        axes[1, 0].set_title('丢包位置标记')
        if packet_loss_info['has_packet_loss']:
            axes[1, 0].legend()
        axes[1, 0].grid(True, alpha=0.3)
    else:
        axes[1, 0].plot(time_axis, signal.data, 'b-', alpha=0.7)
        axes[1, 0].set_xlabel('时间 (秒)')
        axes[1, 0].set_ylabel('幅值')
        axes[1, 0].set_title('信号波形')
        axes[1, 0].grid(True, alpha=0.3)
    
    # 4. 统计信息
    stats_text = f"信号统计信息:\n"
    stats_text += f"采样点数: {signal.length}\n"
    stats_text += f"采样率: {signal.sampling_rate} Hz\n"
    stats_text += f"实际时长: {signal.duration:.2f} s\n"
    stats_text += f"理论时长: {signal.theoretical_duration:.2f} s\n"
    
    if signal.has_timestamps:
        packet_loss_info = signal.detect_packet_loss()
        stats_text += f"时间覆盖率: {packet_loss_info['time_coverage']*100:.1f}%\n"
        stats_text += f"丢包率: {packet_loss_info['packet_loss_ratio']*100:.1f}%\n"
    
    axes[1, 1].text(0.05, 0.95, stats_text, transform=axes[1, 1].transAxes,
                   verticalalignment='top', fontfamily='monospace')
    axes[1, 1].set_xlim(0, 1)
    axes[1, 1].set_ylim(0, 1)
    axes[1, 1].axis('off')
    axes[1, 1].set_title('统计信息')
    
    plt.tight_layout()
    
    if save_path:
        plt.savefig(save_path, dpi=300, bbox_inches='tight')
        print(f"图表已保存到: {save_path}")
    
    plt.show()


def main():
    """主函数：演示时间戳功能的完整使用流程"""
    print("=== PPG信号时间戳处理功能演示 ===\n")
    
    # 1. 创建带丢包的PPG信号
    print("1. 创建模拟PPG信号（包含丢包）...")
    signal_with_loss = create_ppg_with_timestamps(
        duration=30.0,
        sampling_rate=100.0,
        heart_rate=75.0,
        packet_loss_ratio=0.08  # 8%丢包率
    )
    
    # 2. 分析时间戳信号
    print("\n2. 分析时间戳信号...")
    packet_loss_info = analyze_timestamp_signal(signal_with_loss)
    
    # 3. 插值修复
    print("\n3. 执行插值修复...")
    interpolated_signal = demonstrate_interpolation(signal_with_loss)
    
    # 4. 比较处理结果
    print("\n4. 比较处理结果...")
    compare_processing_results(signal_with_loss, interpolated_signal)
    
    # 5. 可视化分析（如果有matplotlib）
    print("\n5. 生成可视化分析...")
    try:
        visualize_timestamp_analysis(signal_with_loss, interpolated_signal)
    except Exception as e:
        print(f"可视化过程中出现错误: {e}")
    
    print("\n=== 演示完成 ===")
    
    return {
        'original_signal': signal_with_loss,
        'interpolated_signal': interpolated_signal,
        'packet_loss_info': packet_loss_info
    }


if __name__ == "__main__":
    # 运行演示
    results = main()